# -*- coding: utf-8 -*-
# @Time    : 2024/11/7 下午1:56
# @Author  : xiaowanzi
# @File    : idCard.py
from base.project_path import get_project_path
import random, datetime

'''
排列顺序从左至右依次为：六位数字地址码，八位数字出生日期码，三位数字顺序码和一位校验码:
1、地址码 
表示编码对象常住户口所在县(市、旗、区)的行政区域划分代码，按GB/T2260的规定执行。
2、出生日期码 
表示编码对象出生的年、月、日，按GB/T7408的规定执行，年、月、日代码之间不用分隔符。 
3、顺序码 
表示在同一地址码所标识的区域范围内，对同年、同月、同日出生的人编定的顺序号，顺序码的奇数分配给男性，偶数分配给女性。 
4、校验码计算步骤
    (1)十七位数字本体码加权求和公式 
    S = Sum(Ai * Wi), i = 0, ... , 16 ，先对前17位数字的权求和 
    Ai:表示第i位置上的身份证号码数字值(0~9) 
    Wi:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 （表示第i位置上的加权因子）
    (2)计算模 
    Y = mod(S, 11)
    (3)根据模，查找得到对应的校验码 
    Y: 0 1 2 3 4 5 6 7 8 9 10 
    校验码: 1 0 X 9 8 7 6 5 4 3 2
'''


def getCheckBit(num17):
    """
    获取身份证最后一位，即校验码
    :param num17: 身份证前17位字符串
    :return: 身份证最后一位
    """
    Wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
    checkCode = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
    zipWiNum17 = zip(list(num17), Wi)
    S = sum(int(i) * j for i, j in zipWiNum17)
    Y = S % 11
    return checkCode[Y]


def getAddrCode(institution=None):
    """
    获取身份证前6位，即地址码
    :return: 身份证前6位
    """
    if institution:
        from base.addr_dict import addr_dict
        addrIndex = random.randint(0, len(addr_dict[institution]) - 1)
        idNumber, addrName = addr_dict[institution][addrIndex]
        return str(idNumber)
    else:
        from base.addr import addr
        addrIndex = random.randint(0, len(addr) - 1)
        idNumber, addrName = addr[addrIndex]
        return str(idNumber)


def getBirthday(start="1970-01-01", end="2000-12-30"):
    """
    获取身份证7到14位，即出生年月日
    :param start: 出生日期合理的起始时间
    :param end: 出生日期合理的结束时间
    :return: 份证7到14位
    """
    days = (datetime.datetime.strptime(end, "%Y-%m-%d") - datetime.datetime.strptime(start, "%Y-%m-%d")).days + 1
    birthday = datetime.datetime.strptime(start, "%Y-%m-%d") + datetime.timedelta(random.randint(0, days))
    return datetime.datetime.strftime(birthday, "%Y%m%d")


# 身份证号
def create_id_card(institution=None):
    """
    获取随机身份证
    :param institution: 类型
    :return: 返回一个随机身份证
    """
    idNumber = getAddrCode(institution)
    idCode = idNumber + getBirthday()
    for i in range(2):
        idCode += str(random.randint(0, 9))
    idCode += str(random.randint(0, 9))
    idCode += getCheckBit(idCode)
    return idCode


# 姓名
def create_name(typ=None):
    xing = ['赵', '钱', '孙', '李', '周', '吴', '郑', '王', '冯', '陈', '褚', '卫', '蒋', '沈', '韩', '杨', '朱', '秦', '尤', '许',
            '何', '吕', '施', '张', '孔', '曹', '严', '华', '金', '魏', '陶', '姜', '戚', '谢', '邹', '喻', '柏', '水', '窦', '章',
            '云', '苏', '潘', '葛', '奚', '范', '彭', '郎', '鲁', '韦', '昌', '马', '苗', '凤', '花', '方', '俞', '任', '袁', '柳',
            '酆', '鲍', '史', '唐', '费', '廉', '岑', '薛', '雷', '贺', '倪', '汤', '滕', '殷', '罗', '毕', '郝', '邬', '安', '常',
            '乐', '于', '时', '傅', '皮', '卞', '齐', '康', '伍', '余', '元', '卜', '顾', '孟', '平', '黄', '和', '穆', '萧', '尹',
            '姚', '邵', '堪', '汪', '祁', '毛', '禹', '狄', '米', '贝', '明', '臧', '计', '伏', '成', '戴', '谈', '宋', '茅', '庞',
            '熊', '纪', '舒', '屈', '项', '祝', '董', '梁']

    ming = ['的', '一', '是', '了', '我', '不', '人', '在', '他', '有', '这', '个', '上', '们', '来', '到', '时', '大', '地',
            '为', '子', '中', '你', '说', '生', '国', '年', '着', '就', '那', '和', '要', '她', '出', '也', '得', '里', '后', '自',
            '以', '会', '家', '可', '下', '而', '过', '天', '去', '能', '对', '小', '多', '然', '于', '心', '学', '么', '之', '都',
            '好', '看', '起', '发', '当', '没', '成', '只', '如', '事', '把', '还', '用', '第', '样', '道', '想', '作', '种', '开',
            '美', '总', '从', '无', '情', '己', '面', '最', '女', '但', '现', '前', '些', '所', '同', '日', '手', '又', '行', '意',
            '动', '方', '期', '它', '头', '经', '长', '儿', '回', '位', '分', '爱', '老', '因', '很', '给', '名', '法', '间', '斯',
            '知', '世', '什', '两', '次', '使', '身', '者', '被', '高', '已', '亲', '其', '进', '此', '话', '常', '与', '活', '正',
            '感', '见', '明', '问', '力', '理', '尔', '点', '文', '几', '定', '本', '公', '特', '做', '外', '孩', '相', '西', '果',
            '走', '将', '月', '十', '实', '向', '声', '车', '全', '信', '重', '三', '机', '工', '物', '气', '每', '并', '别', '真',
            '打', '太', '新', '比', '才', '便', '夫', '再', '书', '部', '水', '像', '眼', '等', '体', '却', '加', '电', '主', '界',
            '门', '利', '海', '受', '听', '表', '德', '少', '克', '代', '员', '许', '稜', '先', '口', '由', '死', '安', '写', '性',
            '马', '光', '白', '或', '住', '难', '望', '教', '命', '花', '结', '乐', '色', '更', '拉', '东', '神', '记', '处', '让',
            '母', '父', '应', '直', '字', '场', '平', '报', '友', '关', '放', '至', '张', '认', '接', '告', '入', '笑', '内', '英',
            '军', '候', '民', '岁', '往', '何', '度', '山', '觉', '路', '带', '万', '男', '边', '风', '解', '叫', '任', '金', '快',
            '原', '吃', '妈', '变', '通', '师', '立', '象', '数', '四', '失', '满', '战', '远', '格', '士', '音', '轻', '目', '条',
            '呢', '病', '始', '达', '深', '完', '今', '提', '求', '清', '王', '化', '空', '业', '思', '切', '怎', '非', '找', '片',
            '罗', '钱', '紶', '吗', '语', '元', '喜', '曾', '离', '飞', '科', '言', '干', '流', '欢', '约', '各', '即', '指', '合',
            '反', '题', '必', '该', '论', '交', '终', '林', '请', '医', '晚', '制', '球', '决', '窢', '传', '画', '保', '读', '运',
            '及', '则', '房', '早', '院', '量', '苦', '火', '布', '品', '近', '坐', '产', '答', '星', '精', '视', '五', '连', '司',
            '巴', '奇', '管', '类', '未', '朋', '且', '婚', '台', '夜', '青', '北', '队', '久', '乎', '越', '观', '落', '尽', '形',
            '影', '红', '爸', '百', '令', '周', '吧', '识', '步', '希', '亚', '术', '留', '市', '半', '热', '送', '兴', '造', '谈',
            '容', '极', '随', '演', '收', '首', '根', '讲', '整', '式', '取', '照', '办', '强', '石', '古', '华', '諣', '拿', '计',
            '您', '装', '似', '足', '双', '妻', '尼', '转', '诉', '米', '称', '丽', '客', '南', '领', '节', '衣', '站', '黑', '刻',
            '统', '断', '福', '城', '故', '历', '惊', '脸', '选', '包', '紧', '争', '另', '建', '维', '绝', '树', '系', '伤', '示',
            '愿', '持', '千', '史', '谁', '准', '联', '妇', '纪', '基', '买', '志', '静', '阿', '诗', '独', '复', '痛', '消', '社',
            '算', '义', '竟', '确', '酒', '需', '单', '治', '卡', '幸', '兰', '念', '举', '仅', '钟', '怕', '共', '毛', '句', '息',
            '功', '官', '待', '究', '跟', '穿', '室', '易', '游', '程', '号', '居', '考', '突', '皮', '哪', '费', '倒', '价', '图',
            '具', '刚', '脑', '永', '歌', '响', '商', '礼', '细', '专', '黄', '块', '脚', '味', '灵', '改', '据', '般', '破', '引',
            '食', '仍', '存', '众', '注', '笔', '甚', '某', '沉', '血', '备', '习', '校', '默', '务', '土', '微', '娘', '须', '试',
            '怀', '料', '调', '广', '蜖', '苏', '显', '赛', '查', '密', '议', '底', '列', '富', '梦', '错', '座', '参', '八', '除',
            '跑', '亮', '假', '印', '设', '线', '温', '虽', '掉', '京', '初', '养', '香', '停', '际', '致', '阳', '纸', '李', '纳',
            '验', '助', '激', '够', '严', '证', '帝', '饭', '忘', '趣', '支', '春', '集', '丈', '木', '研', '班', '普', '导', '顿',
            '睡', '展', '跳', '获', '艺', '六', '波', '察', '群', '皇', '段', '急', '庭', '创', '区', '奥', '器', '谢', '弟', '店',
            '否', '害', '草', '排', '背', '止', '组', '州', '朝', '封', '睛', '板', '角', '况', '曲', '馆', '育', '忙', '质', '河',
            '续', '哥', '呼', '若', '推', '境', '遇', '雨', '标', '姐', '充', '围', '案', '伦', '护', '冷', '警', '贝', '著', '雪',
            '索', '剧', '啊', '船', '险', '烟', '依', '斗', '值', '帮', '汉', '慢', '佛', '肯', '闻', '唱', '沙', '局', '伯', '族',
            '低', '玩', '资', '屋', '击', '速', '顾', '泪', '洲', '团', '圣', '旁', '堂', '兵', '七', '露', '园', '牛', '哭', '旅',
            '街', '劳', '型', '烈', '姑', '陈', '莫', '鱼', '异', '抱', '宝', '权', '鲁', '简', '态', '级', '票', '怪', '寻', '杀',
            '律', '胜', '份', '汽', '右', '洋', '范', '床', '舞', '秘', '午', '登', '楼', '贵', '吸', '责', '例', '追', '较', '职',
            '属', '渐', '左', '录', '丝', '牙', '党', '继', '托', '赶', '章', '智', '冲', '叶', '胡', '吉', '卖', '坚', '喝', '肉',
            '遗', '救', '修', '松', '临', '藏', '担', '戏', '善', '卫', '药', '悲', '敢', '靠', '伊', '村', '戴', '词', '森', '耳',
            '差', '短', '祖', '云', '规', '窗', '散', '迷', '油', '旧', '适', '乡', '架', '恩', '投', '弹', '铁', '博', '雷', '府',
            '压', '超', '负', '勒', '杂', '醒', '洗', '采', '毫', '嘴', '毕', '九', '冰', '既', '状', '乱', '景', '席', '珍', '童',
            '顶', '派', '素', '脱', '农', '疑', '练', '野', '按', '犯', '拍', '征', '坏', '骨', '余', '承', '置', '臓', '彩', '灯',
            '巨', '琴', '免', '环', '姆', '暗', '换', '技', '翻', '束', '增', '忍', '餐', '洛', '塞', '缺', '忆', '判', '欧', '层',
            '付', '阵', '玛', '批', '岛', '项', '狗', '休', '懂', '武', '革', '良', '恶', '恋', '委', '拥', '娜', '妙', '探', '呀',
            '营', '退', '摇', '弄', '桌', '熟', '诺', '宣', '银', '势', '奖', '宫', '忽', '套', '康', '供', '优', '课', '鸟', '喊',
            '降', '夏', '困', '刘', '罪', '亡', '鞋', '健', '模', '败', '伴', '守', '挥', '鲜', '财', '孤', '枪', '禁', '恐', '伙',
            '杰', '迹', '妹', '藸', '遍', '盖', '副', '坦', '牌', '江', '顺', '秋', '萨', '菜', '划', '授', '归', '浪', '听', '凡',
            '预', '奶', '雄', '升', '碃', '编', '典', '袋', '莱', '含', '盛', '济', '蒙', '棋', '端', '腿', '招', '释', '介', '烧', '误',
            '乾', '坤']

    x = random.randint(0, len(xing) - 1)
    m1 = random.randint(0, len(ming) - 1)
    m2 = random.randint(0, len(ming) - 1)
    name = ('' + xing[x] + ming[m1] + ming[m2])
    if typ == "团体":
        return name + name
    else:
        return name


# 手机号
def create_phone():
    # 第二个数字
    second = [3, 4, 5, 7, 8][random.randint(0, 4)]
    # 第三个数字
    third = {3: random.randint(0, 9),
             4: [5, 7, 9][random.randint(0, 2)],
             5: [i for i in range(10) if i != 4][random.randint(0, 8)],
             7: [i for i in range(10) if i not in [4, 9]][random.randint(0, 7)],
             8: random.randint(0, 9), }[second]
    # 最后8位数字
    suffix = random.randint(9999999, 100000000)
    # 拼接手机号
    return "1{}{}{}".format(second, third, suffix)


# 银行卡号
def create_bankAccount():
    # 工行卡号开头
    prefix = "622202"
    # prefix = "622609"  # 招行卡
    for i in range(13):
        prefix = prefix + str(random.randint(0, 9))
    return prefix


# 行政区划码
def get_address(code=False, random_switch=True, all_info=False, **kwargs):
    """

    :param code: 只返回 地区码
    :param random_switch: 自定义区域 然后随机地区
    :param kwargs: province_num = 省 city_info = 市 district_info = 区
    :return: code False 省市区 code True 地区吗
    """
    import json
    with open(get_project_path() + r"\base\address.json", 'r', encoding='UTF-8') as file:
        info = json.load(file)
    i = 0
    province_num = None
    city_info = None
    district_info = None
    error_num = 0
    while True:
        try:
            if random_switch:
                province_num = random.randint(0, len(info) - 1)
            else:
                for address_info in info:

                    if kwargs['province_name'] == address_info['name']:
                        province_num = i
                        break
                    i += 1
            province_date = info[province_num]

            province_name = province_date['name']
            if 'city_name' in kwargs.keys():
                for city in province_date['child']:
                    if city['name'] == kwargs['city_name']:
                        city_info = city
                        break
                city_name = kwargs['city_name']
            else:
                city_info = random.choice(province_date['child'])
                city_name = city_info['name']

            if 'district_name' in kwargs.keys():
                for district in city_info['child']:
                    if district['name'] == kwargs['district_name']:
                        district_info = district
            else:
                district_info = random.choice(city_info['child'])
            district_name = district_info['name'].replace('　', '')
            if code and not all_info:
                return district_info['code']
            elif code and all_info:
                return province_name, city_name, district_name, district_info['code']
            else:
                return province_name, city_name, district_name
        except Exception as e:
            error_num += 1
            if error_num >= 3:
                raise Exception(e)


# 组织机构代码 9位
def create_organization():
    # GB11714-1997全国组织机构代码编制规则中代码字符集
    # string2 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    ORGANIZATION_CHECK_CODE_DICT = {
        '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
        'A': 10, 'B': 11, 'C': 12, 'D': 13, 'E': 14, 'F': 15, 'G': 16, 'H': 17,
        'J': 18, 'K': 19, 'L': 20, 'M': 21, 'N': 22, 'P': 23, 'Q': 24,
        'R': 25, 'T': 26, 'U': 27, 'W': 28, 'X': 29, 'Y': 30}
    weighting_factor = [3, 7, 9, 10, 5, 8, 4, 2]  # Wi 代表第i位上的加权因子=pow(3,i-1)%31
    dict_check = {value: key for key, value in ORGANIZATION_CHECK_CODE_DICT.items()}
    org_code = []  # 组织机构代码列表
    summ = 0
    for i in range(8):
        org_code.append(dict_check[random.randint(0, 30)])  # 前八位本体代码：0~9 + A~Z 31个
        summ = summ + ORGANIZATION_CHECK_CODE_DICT[org_code[i]] * weighting_factor[i]
    C9 = 11 - summ % 11  # 代表校验码：11-MOD（∑Ci(i=1→8)×Wi,11）-->前8位加权后与11取余，然后用11减
    if C9 == 10:
        last_code = 'X'
    elif C9 == 11:
        last_code = '0'
    else:
        last_code = str(C9)

    code = ''.join(org_code) + '-' + last_code  # 组织机构代码
    return code


# 校验位
def gen_check_code(weighting_factor, ontology_code, modulus, check_code_dict):
    """
    统一社会信用代码 + 组织结构代码校验
    @param weighting_factor: 加权因子
    @param ontology_code:本体代码
    @param modulus:  模数(求余用)
    @param check_code_dict: 字符字典
    """
    total = 0
    for i in range(len(ontology_code)):
        if ontology_code[i].isdigit():
            # print(ontology_code[i], weighting_factor[i])
            total += int(ontology_code[i]) * weighting_factor[i]
        else:
            num = check_code_dict.get(ontology_code[i], -1)
            if num < 0:
                return -1
            total += num * weighting_factor[i]
    diff = modulus - total % modulus
    return diff


# 统一社会信用代码 18位
def create_social_credit(nature="企业"):
    """
    机构编制机关：11打头  机构编制事业单位：12打头  机构编制中央编办直接管理机构编制的群众团体：13打头
    机构编制其他：19打头  民政社会团体：51打头  民政民办非企业单位：52打头  民政基金会：53打头
    民政其他：59打头  工商企业：91打头  工商个体工商户：92打头  工商农民专业合作社：93打头  其他：Y1打头
    :return:
    """
    # 统一社会信用代码最后一位：代码字符集
    # string1 = '0123456789ABCDEFGHJKLMNPQRTUWXY'
    head = {
        "机关团体": ["11", "12", "13", "19", "51", "52", "53", "59"],
        "企业": ["91", "92", "93"],
        "其他": ["Y1"]
    }
    SOCIAL_CREDIT_CHECK_CODE_DICT = {
        '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
        'A': 10, 'B': 11, 'C': 12, 'D': 13, 'E': 14, 'F': 15, 'G': 16, 'H': 17,
        'J': 18, 'K': 19, 'L': 20, 'M': 21, 'N': 22, 'P': 23, 'Q': 24,
        'R': 25, 'T': 26, 'U': 27, 'W': 28, 'X': 29, 'Y': 30}
    social_credit_weighting_factor = [1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28]  # 第i位置上的加权因子
    department_agency = head[nature]  # 登记管理部门代码_机构类别
    address_code = get_address(True)  # 登记管理机关行政区划码
    organization_code = create_organization().replace('-', '')  # 组织机构代码
    # 没有校验码的社会统一代码
    un_code = random.choice(department_agency) + str(address_code) + organization_code
    # 校验位
    social_num = gen_check_code(social_credit_weighting_factor, un_code, 31, SOCIAL_CREDIT_CHECK_CODE_DICT)
    if social_num == 31:
        social_num = 0
    social_dict = {value: key for key, value in SOCIAL_CREDIT_CHECK_CODE_DICT.items()}
    # 两位证书 转换成 协议里面的值
    social_key = social_dict[social_num]
    code = un_code + social_key
    return code


def get_vehicleCode():
    # 获取车辆来历凭证编号
    # 从a-zA-Z0-9生成指定数量的随机字符：
    # ''.join(random.sample(string.ascii_letters + string.digits, 12))
    # 多个字符中生成指定数量的随机字符:
    vehicleCode = ""
    for i in range(4):
        vehicleCode += "".join(random.sample('QWERTYUIOPASDFGHJKLZXCVBNMzyxwvutsrqponmlkjihgfedcba0123456789', 3))
    return vehicleCode


if __name__ == "__main__":
    print(create_name("团体"))
    print(create_id_card("湖南"))
    print(create_social_credit())
    print(get_vehicleCode())
